<?php
namespace Application\model;

use Cola\Exception\DbException;
use Cola\Model;
use Cola\Request;

/**
 * 充值基础参数处理
 * 当下面的参数与请求参数不同名时，就需要在子类的initPayParams方法中对其进行赋值
 * @property string $cpid 子包id
 * @property string $ccid 渠道子渠道id
 * @property string $shopId 商品id
 * @property string $orderId 订单号
 * @property string $account 用户帐号ID：用户认证的唯一标识
 * @property string $openId 平台原始账号
 * @property string $amount 人民币金额
 * @property string $sid 区服id
 * @property string $actorId 商品id
 * @property string $actorName 角色id
 * @property string $level 角色等级
 * @property string $vip 角色vip等级
 * @property string $sign 签名
 * @property string $isTest 是否测试订单
 * @property string $time 支付请求时间 unix 时间戳（以秒为单位）
 */
abstract class BasePayModel extends Model
{

    /**
     * 自动设置map
     * @var array
     */
    protected $auto_set_map = [];

    public $table = 'log_payment';

    protected $actorCreateTime='';
    protected $signKey = 'sign';
    protected $cid = '';
    protected $isTest=0;
	public function _init(){

		$this->logfile('#################' . PFORM_NAME . ' pay start################');
        $this->logfile("pay params: " . json_encode(Request::param()));

	}


	public function get($k)
	{

		return Request::param($k);
	}

    //充值ip校验
    public function ipCheck($iplist=[]){
		$ip = ip();
		if(!in_array($ip, $iplist)){
            $this->logfile(PFORM_NAME. " pay ip invalid: " . $ip. "orderId:{$this->orderId} uid:{$this->account} sid:{$this->serverId}", false, true);
			return true;
		}
		return false;
	}


	public function signCheck($echo = false, $exit = false)
    {
        if(($sign = $this->sign()) === true) {return false; }
        if($sign != $this->{$this->signKey}){
            $this->logfile(PFORM_NAME . " sign check error! mySign:$sign sign:{$this->{$this->signKey}}", $echo, $exit);
            return true;
        }
        return false;
	}

    /**
     * 计算签名，如果平台需要签名，则需要重写这个方法
     *
     * @return bool|string 默认为true  以防有些平台不用签名验证
     */
	protected function sign()
    {
        return true;
    }

	public function __get($name = '')
	{
		if(in_array($name, ['db','cache','config','redis'])){
			return parent::__get($name);
		}
		return $this->$name = $this->get($name);
	}

    public function savePayment(){
    	$orderId = $this->orderId;
    	$sid = $this->sid;
    	$account = $this->account;
        $this->updateOrder(['status' => 2, 'pay_dt' => date('Y-m-d H:i:s')]);
		// 加锁
    	$this->logfile("param.....account:{$account} serverId:{$sid} orderId:{$orderId}");

        // 检测订单号是否在订单表
        /* @var \Application\model\BaseOrderModel $m */
        $m = $this->model('Order');
        $orders = $m->getOrderByOrderId($account, $orderId);
        if (empty($orders)) return array('1','orderid empty');
	    $this->db('_logdb')->beginTransaction();
    	$orderInfo = $this->saveToLog($orders);
        $this->db('_logdb')->commit();
        
    	$existed = $orderInfo['existed'];
    	$this->logfile("orderId: [{$orderId}] rmb:{$orderInfo['amount']} account:{$orderInfo['account']} existed: {$orderInfo['existed']}");

        //existed 为0标示订单没有重复
	    if($existed == 0){
            return $this->handleOrder($sid,$orderId,$orders,$orderInfo);
	    }elseif($existed == 1){
	    	$this->logfile('called-back.....success');
			return array('0','called-back');
	    }else{
            $order['status'] = -1;
            $this->updateOrder($order);
            return array('-1','null');
	    }
        return array('0','ok');
	}

	private function handleOrder($sid,$orderId,$orders,$orderInfo){
        $success = $error = ['pay_amount'=>$orderInfo['amount'], 'account_first_pay' => $orderInfo['first_pay'], 'actor_first_pay' => $orderInfo['actor_first_pay'], 'status' => -1];
        $success['status'] = 1;

        $server = $this->model('Server')->getServerBySid($sid);

        $url = $server['ip'].':'. $server['port'].'/pay?playerId='.$this->actorId.'&shopId='.$this->shopId.'&orderNumber='.$orderId.'&param='.$orders['param'];
        // 通知游戏发货
        return $this->serverNotify($url,$success,$error);
        /*$orders = compact('error','success');
        $where['orderid'] = $this->orderId;
        return $this->serverAsynNotify(compact('url','orders','where'));*/

    }
    private function serverNotify($url,$success,$error){
        $ress = curl($url);
        $res = json_decode($ress, true);
        $this->logfile($url.' result:'.$ress);

        if ($res['code'] != 1) {
            $this->updateOrder($error);
            return array('-1', $res['msg']);
        } else {
            $this->updateOrder($success);
        }
        return array('0','ok');
    }

    private function serverAsynNotify($datas){
        $AccountModel = new AccountModel();
        $AccountModel->redis->lpush('report_payment', json_encode($datas));
        return array('0','ok');
    }

	//保存日志
	public function saveToLog($order){
		$data['cid'] = CID; // 渠道id
		$data['cpid'] = $this->cpid; // 发行渠道id
		$data['ccid'] = $this->ccid; // 发行子渠道id
		$data['sid'] = $this->sid; // 游戏服id
		$data['account'] = $this->account; // 账号
		$data['actor_id'] = $this->actorId; //角色ID
        $data['actor_name'] = $this->actorName ?? $order['actor_name']; //角色名
		$data['amount'] = $this->amount; // 金额
		$data['pay_datedt'] = date('Y-m-d H:i:s'); // 充值时间
		$data['orderid'] = $this->orderId; // 订单ID
		$data['reg_date'] = $this->actorCreateTime; //角色创建时间
		$data['recharge_id'] = $this->shopId; // 档位ID
		$data['recharge_name'] = $order['recharge_name']; // 档位名
		$data['is_test'] = $this->isTest; // 是否测试订单
		$data['level'] = $order['level']; // 等级
		$data['vip'] = $order['vip']; // vip
		$data['create_order_dt'] = $order['create_dt']; // 订单创建时间
		//订单是否重复
		$existed = 0;
        if ($this->hasPaymentLog($this->orderId)) {
            $data['existed'] = 1;
            return $data;
        }
        //检查是否首充
	    $a_table = "accounts";
        $a_data = array();
        $a_data['account'] = $this->account;
        $a_data['sid'] =  $this->sid;
        $a_data['actor_id'] =  $this->actorId;
        $isActorFirstPay = $this->checkActorFirstPay($a_data,$a_table);
        $data['actor_first_pay'] = $isActorFirstPay ? 0 : 1;
        $a_count = $this->checkFirstPay($a_data,$a_table);
        if($a_count > 0 ){
        	$first_pay = 0;
        }else{
        	$first_pay = 1;
        }
		$data['first_pay'] = $first_pay;
	    // 写入数据库
		$inserId = $this->db('_logdb')->insert($data, $this->table);

		if(!$inserId){
		    $this->db('_logdb')->rollback();
			$data['existed'] = -1;
			return $data;
		}

		$data['existed'] = $existed;
		//返回订单信息
		return $data;
	}

    public function updateOrder($data)
    {
        $this->db('_logdb')->update($data, ["orderid = ?",[$this->orderId]], 'log_order');
    }

	//根据订单号检查是否存在
	public function hasPaymentLog($orderId){
		$sql = "SELECT id FROM {$this->table} WHERE orderid='{$orderId}'";
		return (bool) $this->db('_logdb')->col($sql);
	}

	//检查是否首充
	public function checkFirstPay($data,$a_table) {
        $cid = realCID();
		$where = " account=? AND cid=?";
		$value = [$data['account'],$cid];
		$sql = "SELECT is_paid FROM {$a_table} WHERE {$where}  and is_paid=1";
		$res = $this->db->col($sql,$value);
        if($res == 0){
        	//修改is_paid 字段 为1
            $where .= " and sid=?";
            $value[] = $data['sid'];
        	$this->db->update(['is_paid'=>1], [$where,$value], $a_table);
            return 0;
        }elseif($res == 1){
        	return 1;
        }
		return -1;
	}

    public function checkActorFirstPay($data,$a_table)
    {
        $cid = realCID();
        $where = "account=? AND cid=? AND actor_id=? and is_paid=1";
        $value = [$data['account'],$cid,$data['actor_id']];
        $sql = "SELECT is_paid FROM {$a_table} WHERE $where";
        return $this->db->col($sql,$value);

    }

    public function __errmsg($status, $isdebug = false)
    {
        echo $status;

        $isdebug OR exit;
    }

	public function initPayCallBack()
    {
        $this->autoSet();
        $this->initPayParams();
        $ChannelModel = new ChannelModel();
        $channel = $ChannelModel->getChannelInfo();
        $this->cid = $channel['cid'];

        $this->account = $ChannelModel->realAccount($this->account,$this->cid);
        // 获取角色信息
        /* @var AccountModel $role_model */
        $AccountModel = $this->model('Account');

        $accountInfo = $AccountModel->getAccountInfo($this->account, $this->sid, $this->actorId);
        if(empty($accountInfo) || $accountInfo['status'] == 0){
            $this->logfile('role null');
            return 'role null';
        }
        $this->actorCreateTime = $accountInfo['create_time'];
        $this->logfile('checked account');
        return false;
    }

    /**
     * 根据配置自动匹配请求参数与项目字段
     * @return void
     */
    protected function autoSet()
    {
        foreach($this->auto_set_map as $field => $param)
        {
            $this->$field = $this->$param;
        }
    }

    /**
     * 初始化支付回调参数
     * @return void
     */
    abstract protected function initPayParams();

    public function getRechargeConfig($shopId = 0)
    {
        $shopSql = "select * from cfg_channel_recharge where id = ? and cid = ?";
        $cidSql = "select * from cfg_channel_recharge where cid = ?";
        if($shopId){
            $item = $this->db('_backdb')->row($shopSql,[$shopId,CID]);
            if(!$item){
                $item = $this->db('_backdb')->row($shopSql,[$shopId,'']);
                if(!$item){
                    $this->logfile('RechargeConfig error:' .$shopId.':'.CID);
                }
            }
            return $item;
        }else{
            $recharges = $this->db('_backdb')->sql($cidSql,[CID]);
            if(!$recharges){
                $recharges = $this->db('_backdb')->sql($cidSql,['']);
            }
            return $recharges ? array_column($recharges,null,'id') : [];
        }

        return [];

    }

    public function checkAmount()
    {
        if(($check = $this->config->get('amountChecker')) && is_callable($check)) {
            $res = $check($this->amount);

            if($res === false) {
                $this->logfile('amount error');
                return 0;
            }
        }
    }

    public function checkProduct(): array
    {
        $config = $this->getRechargeConfig($this->shopId);
        if (empty($config)){
            $this->logfile("orderId:{$this->orderId} uid:{$this->role} shopId:{$this->shopId} invalid, config empty");
            return [];
        }
        return $config;
    }

}